import CodeMirror from "./codemirror/lib/codemirror.js";

// import "./codemirror/addon/edit/closetag.js";//
// import "./codemirror/addon/selection/active-line.js";//编辑行高亮
// import "./codemirror/addon/edit/matchbrackets.js";//花括号匹配

import format from "./codemirror/lib/formatting.js";
format(CodeMirror);
import "./codemirror/addon/hint/show-hint.js";
// // import "codemirror/addon/hint/anyword-hint.js";

//代码折叠
import "./codemirror/addon/fold/foldcode.js"; //
import "./codemirror/addon/fold/foldgutter.js"; //
import "./codemirror/addon/fold/brace-fold.js"; //

// //js 模块
import "./codemirror/mode/javascript/javascript.js"; //js 模块
import "./codemirror/addon/hint/javascript-hint.js"; //js代码提示
import { JSHINT } from "./codemirror/lib/jshint.js"; //js语法检查

// sql 模块
import "./codemirror/mode/sql/sql.js";
import "./codemirror/addon/hint/sql-hint.js";
import sqlFormatter from "./codemirror/lib/sql-formatter.js";

export default {
  props: ["mode", "modelValue", "readOnly", "option"],
  emits: ["update:modelValue"],
  data() {
    return {
      editor: null,
      optionDefault: {
        // mode: "text/x-mysql", //编辑器模式
        mode: "javascript",
        // mode: "application/json",
        flattenSpans: false, //相同class的两个span合并成一个
        readOnly: false, //只读
        lineNumbers: true, //显示代码行
        lineWrapping: false, //自动换行
        extraKeys: {
          "Ctrl-S": function(cm) {
            cm.save();
          },
          //格式化
          "Alt-F": this.format,
          //代码折叠
          "Ctrl-Q": function(cm) {
            cm.foldCode(cm.getCursor());
          }
          // Tab键换成4个空格
          // Tab: function (cm) {
          //   var spaces = Array(cm.getOption("indentUnit") + 1).join(" ");
          //   cm.replaceSelection(spaces);
          // },
          // // F11键切换全屏
          // "F11": function (cm) {
          // //   cm.setOption("fullScreen", !cm.getOption("fullScreen"));
          // },
          // // Esc键退出全屏
          // "Esc": function (cm) {
          //   if (cm.getOption("fullScreen")) cm.setOption("fullScreen", false);
          // }
        },
        foldGutter: true,
        gutters: ["CodeMirror-linenumbers", "CodeMirror-foldgutter"],
        theme: "default", // 编辑器 主题
        styleActiveLine: true, // 当前行背景高亮
        matchBrackets: true, // 括号匹配
        autoCloseTags: true //自动闭合标签
      },
      widgets: []
    };
  },
  computed: {
    needJsHint() {
      let mode = this.editor ? this.editor.getMode() : {};
      return mode.name == "javascript" && !mode.jsonMode;
    }
  },
  watch: {
    // value: {
    //   handler(fresh, old) {
    //     this.setValue();
    //   },
    //   immediate: true
    // }
  },
  mounted() {
    this.initIDE();
    this.editor.on("beforeChange", this.editorBeforeChange);
    this.editor.on("cursorActivity", this.editorCursorActivity);
    this.editor.on("change", (cm, changeObj) => {
      // console.log("[change", cm.getValue(), cm, changeObj);
      this.$emit && this.$emit("update:modelValue", cm.getValue());
    });
    this.setValue();
  },
  methods: {
    formatSQL() {
      let editor = this.editor;
      editor.setValue(sqlFormatter.format(editor.getValue()));
    },
    format() {
      let editor = this.editor;
      if (editor.getMode().name == "sql") {
        return this.formatSQL();
      }
      editor.save();
      let totalLines = editor.lineCount();

      let from = { line: 0, ch: 0 };
      let to = { line: totalLines };
      let cursorStart = editor.getCursor(true);
      let cursorEnd = editor.getCursor(false);
      // let selection = editor.getSelection();
      // if (selection) {
      //     from = editor.getCursor(true);
      //     to = editor.getCursor(false);
      // }
      editor.setSelection(cursorEnd, cursorEnd);
      editor.autoFormatRange(from, to);
      editor.setSelection(cursorStart, cursorEnd);
      editor.autoFormatRange(editor.getCursor(true), eaditor.getCursor(false));
    },
    setValue() {
      // console.log('[setValue]', this.value);
      let valueStr = this.modelValue || "";
      this.editor && this.editor.setValue(valueStr);
    },

    editorBeforeChange(cm, changeObj) {
      var selection = cm.getSelection();
      // console.log('[editorBeforeChange]', cm, changeObj, selection);
      if ((selection && changeObj.text[0] == '"') || changeObj.text[0] == "'") {
        changeObj.text[0] = changeObj.text[0] + selection + changeObj.text[0];
      }
      if (selection && changeObj.text[0] == "(") {
        changeObj.text[0] = "(" + selection + ")";
      }
      if (selection && changeObj.text[0] == "[") {
        changeObj.text[0] = "[" + selection + "]";
      }
      if (selection && changeObj.text[0] == "{") {
        changeObj.text[0] = "{" + selection + "}";
      }
      if (selection && changeObj.text[0] == "<") {
        changeObj.text[0] = "<" + selection + ">";
      }
    },
    editorCursorActivity(cm, changeObj) {
      var mode = cm.getMode().name;
      // console.log(cm, mode);
      if (mode == "markdown") {
        // markdown 不进行代码提示
        return;
      }
      //获取用户当前的编辑器中的编写的代码
      var words = cm.getValue() + "";
      //利用正则取出用户输入的所有的英文的字母
      words = words.replace(/[a-z]+[\-|\']+[a-z]+/gi, "").match(/([a-z]+)/gi);
      //将获取到的用户的单词传入CodeMirror,并在javascript-hint中做匹配

      var keyWords = {};
      for (const i in words) {
        keyWords[words[i]] = true;
      }
      cm.showHint({
        // words: keyWords,
        hint: CodeMirror.hint[mode],
        completeSingle: false
      });
      if (this.needJsHint && this.hintJs) {
        // markdown 不进行代码提示
        // this.jsHints();
      }
    },
    jsHints() {
      //js代码检查
      let editor = this.editor;
      if (!editor) return;
      let widgets = this.widgets;
      for (var i = 0; i < widgets.length; ++i) {
        editor.removeLineWidget(widgets[i]);
      }
      // console.log(editor)
      if (!this.needJsHint || !this.hintJs) {
        return; //不做js代码检查
      }
      editor.operation(function() {
        widgets.length = 0;
        var option = {
          // quotmark: false
        };
        JSHINT(editor.getValue(), option);
        for (var i = 0; i < JSHINT.errors.length; ++i) {
          var err = JSHINT.errors[i];
          if (!err) continue;
          var msg = document.createElement("div");
          var icon = msg.appendChild(document.createElement("span"));
          icon.innerHTML = "!";
          icon.className = "lint-error-icon";
          msg.appendChild(document.createTextNode(err.reason));
          msg.className = "lint-error";
          widgets.push(editor.addLineWidget(err.line - 1, msg, { coverGutter: false, noHScroll: true }));
        }
      });
      var info = editor.getScrollInfo();
      var after = editor.charCoords({ line: editor.getCursor().line + 1, ch: 0 }, "local").top;
      if (info.top + info.clientHeight < after) {
        editor.scrollTo(null, after - info.clientHeight + 3);
      }
    },
    initIDE() {
      let option = Object.assign({}, this.optionDefault, this.option);
      this.mode && (option.mode = this.mode);
      this.editor = CodeMirror.fromTextArea(this.$refs["editor"], option);

      window.IDE = this;
    }
  }
};
